/*
 * copyright (c) 2013 Blaise-Florentin Collin
 *
 * This file is part of astroDCAM.
 *
 * AstroAviBrowser is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License v3
 * as published by the Free Software Foundation
 *
 * AstroAviBrowser is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * v3 along with AstroAviBrowser; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301 USA
 */

///
/// \file QAstroCameraTab.cpp
/// \brief Camera tab widget
///

// C++ includes
#include <vector>

// Qt includes
#include <QMessageBox>

// C++ app includes
#include "config.hpp"

// Qt app includes
#include "QAstroCameraTab.hpp"

// Public methods

//
// Main constructor
//
QAstroCameraTab::QAstroCameraTab(dc1394bus* bus,QWidget* p) : QAstroTab(p) {
   TRACE("[QAstroCameraTab] : Constructor")
   guiReady=false;
   mainBus=bus;
   mainCam=NULL;
   cameraChooser=NULL;
   busReset=NULL;
   modeChooser=NULL;
   rateChooser=NULL;
   currentFrame=NULL;

   // init the frame timer
   frameTimer=new QTimer;
   frameTimer->stop();
   connect(frameTimer,SIGNAL(timeout()),this,SLOT(grabFrame()));
}

//
// Main destructor
//
QAstroCameraTab::~QAstroCameraTab() {
   TRACE("[QAstroCameraTab] : Destructor")

   // release the timer
   frameTimer->stop();
   delete frameTimer;

   // release the current frame
   if(currentFrame!=NULL) delete currentFrame;

   // release dc1394
   if(mainCam!=NULL) {
      if (mainCam->getStreamState()) stopCapture();
      mainBus->releaseCamera(mainCam);
   }
}

//
// Build GUI
//
int QAstroCameraTab::buildGUI() {
   QAstroTab::buildGUI();
   TRACE("[QAstroCameraTab] : Build GUI")

   // camera combobox
   cameraChooser=new QComboBox;
   layout->addWidget(cameraChooser);
   // bus reste button
   busReset=new QPushButton(tr("Rescan"));
   layout->addWidget(busReset);
   // mode combobox
   modeChooser=new QComboBox;
   layout->addWidget(modeChooser);
   // rate combobox
   rateChooser=new QComboBox;
   layout->addWidget(rateChooser);
   // capture button
   captureButton=new QPushButton(tr("Capture : OFF"));
   layout->addWidget(captureButton);
   captureButton->setCheckable(true);

   // init combos
   resetCameraList();
   connect(cameraChooser,SIGNAL(currentIndexChanged(int)),this,SLOT(changeCam(int)));
   connect(busReset,SIGNAL(released()),this,SLOT(resetBus()));
   connect(modeChooser,SIGNAL(currentIndexChanged(int)),this,SLOT(changeMode(int)));
   connect(rateChooser,SIGNAL(currentIndexChanged(int)),this,SLOT(changeRate(int)));
   connect(captureButton,SIGNAL(toggled(bool)),this,SLOT(changeCapture(bool)));

   guiReady=true;

   return(0);
}

// Private methods

//
// Reset the camera combobox
//
void QAstroCameraTab::resetCameraList() {
   TRACE("[QAstroCameraTab] : Reset camera list")

   // clear the combo
   cameraChooser->clear();
   // get the camera list
   cameraList=mainBus->getCameraList();
   if(cameraList.size()==0) {
      QMessageBox::critical(0,"astroDCAM",tr("No camera found, leaving..."));
      exit(_NO_CAMERA_);
   }
   // add the cameras to the combo
   for(int i=0; i < cameraList.size(); i++)
      cameraChooser->addItem(QString(cameraList[i].cameraModel.c_str()));
   cameraChooser->setDisabled(cameraList.size()==1);
   cameraChooser->setCurrentIndex(0);

   // create the new cam
   if(!guiReady) {
      if(setCam(cameraList[0].cameraGuid)!=_NO_ERROR_) {
         QMessageBox::critical(0,"astroDCAM",tr("Unable to init the camera, leaving..."));
         exit(_NO_CAMERA_);
      }
   }
}

//
// Reset the mode combobox
//
void QAstroCameraTab::resetModeList() {
   TRACE("[QAstroCameraTab] : Reset mode list")

   // clear the combo
   modeChooser->clear();
   // get the mode list
   modeList=mainCam->getSupportedModes();
   if(modeList.size()==0) {
      QMessageBox::critical(0,"astroDCAM",tr("No supported video mode found, leaving..."));
      exit(_NO_VIDEOMODE_);
   }
   // add the modes to the combo
   for(int i=0;i<modeList.size();i++)
      modeChooser->addItem(QString(modeList[i].name.c_str()));
   modeChooser->setDisabled(modeList.size()==1);
   modeChooser->setCurrentIndex(0);

   // set the new mode
   if(!guiReady) {
      if(setMode(modeList[0].index)!=_NO_ERROR_) {
         QMessageBox::critical(0,"astroDCAM",tr("Unable to set the video mode, leaving..."));
         exit(_NO_VIDEOMODE_);
      }
   }
}

//
// Reset the frame rate list
//
void QAstroCameraTab::resetRateList() {
   TRACE("[QAstroCameraTab] : Reset frame rate list")

   // clear the combo
   rateChooser->clear();
   // get the mode list
   rateList=mainCam->getSupportedRates();
   if(rateList.size()==0) {
      QMessageBox::critical(0,"astroDCAM",tr("No supported frame rate found, leaving..."));
      exit(_NO_VIDEORATE_);
   }
   // add the modes to the combo
   for(int i=0;i<rateList.size();i++)
      rateChooser->addItem(QString(rateList[i].name.c_str()));
   rateChooser->setDisabled(rateList.size()==1);
   rateChooser->setCurrentIndex(0);

   // set the new mode
   if(!guiReady) {
      if(setRate(rateList[0].index)!=_NO_ERROR_) {
         QMessageBox::critical(0,"astroDCAM",tr("Unable to set the frame rate mode, leaving..."));
         exit(_NO_VIDEORATE_);
      }
   }
}

//
// Set the cam
//
dc1394error QAstroCameraTab::setCam(uint64_t cam) {
   TRACE("[QAstroCameraTab] : Set camera")

   if(mainCam!=NULL) {
      captureButton->setChecked(false);
      changeCapture(false);
      mainBus->releaseCamera(mainCam);
      mainCam=NULL;
   }
   mainCam=mainBus->getCamera(cam);

   if(mainCam!=NULL) {
      resetModeList();
      return(_NO_ERROR_);
   }
   return(_NO_CAMERA_);
}

//
// Set the mode
//
dc1394error QAstroCameraTab::setMode(int mode) {
   TRACE("[QAstroCameraTab] : Set mode")

   if(mainCam!=NULL) {
      dc1394error err;
      err=mainCam->setMode(mode);
      if(err==_NO_ERROR_)
         resetRateList();
      return(err);
   } else
      return(_NO_CAMERA_);
}

//
// Set the frame rate
//
dc1394error QAstroCameraTab::setRate(int rate) {
   dc1394error res;
   TRACE("[QAstroCameraTab] : Set frame rate")

   if(mainCam!=NULL) {
      captureButton->setChecked(false);
      changeCapture(false);
      res=mainCam->setRate(rate);
      if(res==_NO_ERROR_) frameTimer->setInterval(mainCam->getRate().value);
      return(res);
   }
   else
      return(_NO_CAMERA_);
}

//
// Start capture
//
dc1394error QAstroCameraTab::startCapture() {
   dc1394error res;
   TRACE("[QAstroCameraTab] : Start capture")
   if(mainCam!=NULL) {
      res=mainCam->startCapture();
      if(res==_NO_ERROR_) frameTimer->start();
      return(res);
   } else
      return(_NO_CAMERA_);
}

//
// Stop capture
//
dc1394error QAstroCameraTab::stopCapture() {
   dc1394error res;
   TRACE("[QAstroCameraTab] : Stop capture")
   if(mainCam!=NULL) {
      res=mainCam->stopCapture();
      if(res==_NO_ERROR_) frameTimer->stop();
      return(res);
   } else
      return(_NO_CAMERA_);
}

// private slots

//
// Reset bus slot
//
void QAstroCameraTab::resetBus() {
   if(mainCam!=NULL) {
      if(mainCam->getStreamState()) stopCapture();
      mainBus->releaseCamera(mainCam);
   }
   mainCam=NULL;
   mainBus->reset();
   resetCameraList();
}

//
// Camera changing slots
//
void QAstroCameraTab::changeCam(int index) {
   // ignore if combo reset
   if(index==-1)
      return;

   TRACE("[QAstroCameraTab] : Camera changed to " << cameraList[index].cameraModel)

   if(setCam(cameraList[index].cameraGuid)!=_NO_ERROR_) {
      QMessageBox::critical(0,"astroDCAM",tr("Unable to init the camera, leaving..."));
      exit(_NO_CAMERA_);
   }
}

//
// Mode changing slot
//
void QAstroCameraTab::changeMode(int index) {
   // ignore if combo reset
   if(index==-1)
      return;

   TRACE("[QAstroCameraTab] : Mode changed to " << modeList[index].name)

   if(setMode(modeList[index].index)!=_NO_ERROR_) {
      QMessageBox::critical(0,"astroDCAM",tr("Unable to init the video mode, leaving..."));
      exit(_NO_VIDEOMODE_);
   }
}

//
// Frame rate changing slot
//
void QAstroCameraTab::changeRate(int index) {
   // ignore if combo reset
   if(index==-1)
      return;

   TRACE("[QAstroCameraTab] : Frame rate changed to " << rateList[index].name)

   if(setRate(rateList[index].index)!=_NO_ERROR_) {
      QMessageBox::critical(0,"astroDCAM",tr("Unable to set the frame rate, leaving..."));
      exit(_NO_VIDEORATE_);
   }
}

//
// Capture button toggling slot
//
void QAstroCameraTab::changeCapture(bool checked) {
   if(checked) {
      captureButton->setText(tr("Capture : ON"));
      if ( mainCam!=NULL && !mainCam->getStreamState()) startCapture();
   } else {
      captureButton->setText(tr("Capture : OFF"));
      if (mainCam!=NULL && mainCam->getStreamState()) stopCapture();
   }
}

//
// Grab a new frame at QTimer timeout
//
void QAstroCameraTab::grabFrame() {
   if(mainCam!=NULL) {
      TRACE("[QAstroCameraTab] : Grabbing a frame")

      if(currentFrame!=NULL) delete currentFrame;
      currentFrame=mainCam->grabFrame();

      // TO DO

   }
}
